﻿#include "xscale_p.h"

XScalePrivate::XScalePrivate()
    : mainScaleNumber(11),
      subScaleNumber(4),
      maximumRange(10),
      minimumRange(0),
      unitStringEnable(true),
      unitString("cm"),
      unitStringColor(Qt::black),
      mainScaleColor(Qt::black),
      baseScaleColor(Qt::black),
      scaleValueColor(Qt::black),
      scaleDirection(Face_UP),
      scaleValueReverseOrder(false),
      backgroundColor(Qt::transparent),
      borderColor(Qt::transparent),
      LeftmousePressed(false),
      mousePressPoint(0, 0)
{
    borderRadius = 5;
    borderWidth = 5;
    margin = 5;
    precision = 2;
    unitStringWidth = 0;
    unitStringHeight = 0;
    scaleValueWidth = 0;
    scaleValueHeight = 0;
}

XScalePrivate::~XScalePrivate()
{

}

XScale::XScale(QWidget *parent, Qt::WindowFlags f)
    : QLabel(parent, f),
      xScaleP(new XScalePrivate)
{

}

XScale::~XScale()
{

}

/*!
    \property XScale::mainScaleNumber
    \brief the quantity of the mainScale

    The default mainScaleNumber is 11.

    \sa indent
*/
int XScale::getMainScaleNumber() const
{
    return xScaleP->mainScaleNumber;
}

void XScale::setMainScaleNumber(int num)
{
    // 主刻度数的范围为：2-50
    (num < 2) ? (num = 2) : num;
    (num > 50) ? (num = 50) : num;

    if(xScaleP->mainScaleNumber == num)
        return;

    xScaleP->mainScaleNumber = num;
    this->update();
}

/*!
    \property XScale::subScaleNumber
    \brief the quantity of the subScale

    The default subScaleNumber is 4.

    \sa indent
*/
int XScale::getSubScaleNumber() const
{
    return xScaleP->subScaleNumber;
}

void XScale::setSubScaleNumber(int num)
{
    // 副刻度数的范围为：0-50
    (num < 0) ? (num = 0) : num;
    (num > 50) ? (num = 50) : num;

    if(xScaleP->subScaleNumber == num)
        return;

    xScaleP->subScaleNumber = num;
    this->update();
}

/*!
    \property XScale::maximumRange
    \brief the maximumRange of the scale

    The default maximumRange is 100.

    \sa indent
*/
int XScale::getMaximumRange() const
{
    return xScaleP->maximumRange;
}

void XScale::setMaximumRange(int range)
{
    // 最大量程的范围为：1-10000
    (range < 1) ? (range = 1) : range;
    (range > 10000) ? (range = 10000) : range;

    if(xScaleP->maximumRange == range)
        return;

    xScaleP->maximumRange = range;
    this->update();
}

/*!
    \property XScale::minimumRange
    \brief the minimumRange of the scale

    The default minimumRange is 0.

    \sa indent
*/
int XScale::getMinimumRange() const
{
    return xScaleP->minimumRange;
}

void XScale::setMinimumRange(int range)
{
    // 最小量程的范围为：0-9999
    (range < 0) ? (range = 0) : range;
    (range > 9999) ? (range = 9999) : range;

    if(xScaleP->minimumRange == range)
        return;

    xScaleP->minimumRange = range;
    this->update();
}

/*!
    \property XScale::precision
    \brief the precision of the scaleValue

    The default precision is 0.

    \sa indent
*/
int XScale::getPrecision() const
{
    return xScaleP->precision;
}

void XScale::setPrecision(int prec)
{
    // 精确度的范围为：0-4
    (prec < 0) ? (prec = 0) : prec;
    (prec > 4) ? (prec = 4) : prec;

    if(xScaleP->precision == prec)
        return;

    xScaleP->precision = prec;
    this->update();
}

/*!
    \property XScale::unitStringEnable
    \brief the enable of the unitString

    The default unitStringEnable is true.

    \sa indent
*/
bool XScale::getUnitStringEnable() const
{
    return xScaleP->unitStringEnable;
}

void XScale::setUnitStringEnable(bool enable)
{
    if(xScaleP->unitStringEnable == enable)
        return;

    xScaleP->unitStringEnable = enable;
    this->update();
}

/*!
    \property XScale::unitString
    \brief the string of the unit

    The default unitString is "cm".

    \sa indent
*/
QString XScale::getUnitString() const
{
    return xScaleP->unitString;
}

void XScale::setUnitString(const QString string)
{
    if(xScaleP->unitString == string)
        return;

    xScaleP->unitString = string;
    this->update();
}

/*!
    \property XScale::unitStringColor
    \brief the color of the unitString

    The default unitStringColor is black.

    \sa indent
*/
QColor XScale::getUnitStringColor() const
{
    return xScaleP->unitStringColor;
}

void XScale::setUnitStringColor(const QColor &color)
{
    if(xScaleP->unitStringColor == color)
        return;

    xScaleP->unitStringColor = color;
    this->update();
}

/*!
    \property XScale::mainScaleColor
    \brief the color of the mainScale

    The default mainScaleColor is black.

    \sa indent
*/
QColor XScale::getMainScaleColor() const
{
    return xScaleP->mainScaleColor;
}

void XScale::setMainScaleColor(const QColor &color)
{
    if(xScaleP->mainScaleColor == color)
        return;

    xScaleP->mainScaleColor = color;
    this->update();
}

/*!
    \property XScale::baseScaleColor
    \brief the color of the baseScale

    The default baseScaleColor is black.

    \sa indent
*/
QColor XScale::getBaseScaleColor() const
{
    return xScaleP->baseScaleColor;
}

void XScale::setBaseScaleColor(const QColor &color)
{
    if(xScaleP->baseScaleColor == color)
        return;

    xScaleP->baseScaleColor = color;
    this->update();
}

/*!
    \property XScale::scaleValueColor
    \brief the color of the scaleValue

    The default scaleValueColor is black.

    \sa indent
*/
QColor XScale::getScaleValueColor() const
{
    return xScaleP->scaleValueColor;
}

void XScale::setScaleValueColor(const QColor &color)
{
    if(xScaleP->scaleValueColor == color)
        return;

    xScaleP->scaleValueColor = color;
    this->update();
}

/*!
    \property XScale::scaleDirection
    \brief the direction of the scale

    The default scaleDirection is To_Right.

    \sa indent
*/
ScaleChartDirection XScale::getScaleDirection() const
{
    return xScaleP->scaleDirection;
}

void XScale::setScaleDirection(const ScaleChartDirection type)
{
    if(xScaleP->scaleDirection == type)
        return;

    xScaleP->scaleDirection = type;
    this->update();
}

/*!
    \property XScale::scaleValueReverseOrder
    \brief the order of the scaleValue

    The default scaleValueReverseOrder is false.

    \sa indent
*/
bool XScale::getScaleValueReverseOrder() const
{
    return xScaleP->scaleValueReverseOrder;
}

void XScale::setScaleValueReverseOrder(bool order)
{
    if(xScaleP->scaleValueReverseOrder == order)
        return;

    xScaleP->scaleValueReverseOrder = order;
    this->update();
}

/*!
    \property XScale::borderColor
    \brief the color of the border

    The default borderColor is Qt::transparent.

    \sa indent
*/
QColor XScale::getBorderColor() const
{
    return xScaleP->borderColor;
}

void XScale::setBorderColor(const QColor &color)
{
    if(xScaleP->borderColor == color)
        return;

    xScaleP->borderColor = color;
    this->update();
}

/*!
    \property XScale::getBackgroundColor
    \brief the color of the backgroundColor

    The default backgroundColor is Qt::transparent.

    \sa indent
*/
QColor XScale::getBackgroundColor() const
{
    return xScaleP->backgroundColor;
}

void XScale::setBackgroundColor(const QColor &color)
{
    if(xScaleP->backgroundColor == color)
        return;

    xScaleP->backgroundColor = color;
    this->update();
}

/*!
    \reimp
*/
void XScale::paintEvent( QPaintEvent *ev)
{
    Q_UNUSED(ev);

    //绘制准备工作,启用反锯齿
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    //绘制边框
    drawBorder(&painter);

    //绘制底色
    drawBg(&painter);

    //绘制标尺
    drawRuler(&painter);

//    QLabel::paintEvent(ev);
}

/*!
 * \brief XScale::drawRuler
 * \param painter
 */
void XScale::drawRuler(QPainter *painter)
{
    painter->save();

    //1. 获取刻度值单位参数
    getUnitStringParameters(painter);
    //画刻度值单位
    if(xScaleP->unitStringEnable)
    {
        painter->setPen(xScaleP->unitStringColor);
        painter->drawText(xScaleP->unitStringPoint, xScaleP->unitString);
    }

    //2. 获取刻度值参数
    getScaleValueParameters(painter);

    //3. 获取基线起始点和终止点和长度参数
    getBaseLineParameters();
    //画基线
    painter->setPen(xScaleP->baseScaleColor);
    painter->drawLine(xScaleP->baseLineStartPoint, xScaleP->baseLineEndPoint);

    //4. 绘制刻度
    //计算总刻度数
    xScaleP->totalScaleNumber = xScaleP->mainScaleNumber + xScaleP->subScaleNumber * (xScaleP->mainScaleNumber - 1);
    //计算分度值
    xScaleP->divisionValue = xScaleP->baseLineLength / (xScaleP->totalScaleNumber - 1);

    //获取主刻度线长度参数
    getScaleLineLength();

    //画主刻度线副刻度线和刻度值
    for(int i = 0; i < xScaleP->totalScaleNumber; i++)
    {
        QPointF scaleLineStartPoint;
        QPointF scaleLineEndPoint;
        QString scaleValueText;
        QPointF scaleValueTextPoint;

        //获取刻度线起始点和终止点坐标参数
        getScaleLinePoint(painter, scaleLineStartPoint, scaleLineEndPoint, i);
        //画刻度线
        painter->drawLine(scaleLineStartPoint, scaleLineEndPoint);

        //获取刻度值字符串参数
        getScaleValueTextPoint(painter, scaleValueText, scaleValueTextPoint, scaleLineEndPoint, i);
        //画刻度值
        painter->drawText(scaleValueTextPoint, scaleValueText);
    }

    painter->restore();
}

/*!
 * \brief XScale::drawBorder
 * \param painter
 */
void XScale::drawBorder(QPainter *painter)
{
    painter->save();

    painter->setPen(QPen(xScaleP->borderColor, xScaleP->borderWidth));
    painter->setBrush(Qt::NoBrush);

    QPointF topLeft(0, 0);
    QPointF bottomRight(width(), height());
    QRectF rect(topLeft, bottomRight);

    painter->drawRoundedRect(rect, 5, 5);

    painter->restore();
}

/*!
 * \brief XScale::drawBg
 * \param painter
 */
void XScale::drawBg(QPainter *painter)
{
    painter->save();

    QPointF topLeft(this->margin(), this->margin());
    QPointF bottomRight(width() - this->margin(), height() - this->margin());
    QRectF bgRect(topLeft, bottomRight);
    QBrush bgBrush(Qt::transparent);
    painter->setPen(Qt::NoPen);
    painter->setBrush(bgBrush);
    painter->drawRoundedRect(bgRect, xScaleP->borderRadius, xScaleP->borderRadius);

    painter->restore();
}

/*!
 * \brief XScale::enterEvent
 * \param ev
 */
void XScale::enterEvent(QEvent *ev)
{
    if(QEvent::Enter == ev->type())
    {
        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::PointingHandCursor);  //设置光标形状(指)
        setCursor(cursor);                        //使用光标
    }
}

/*!
 * \brief XScale::leaveEvent
 * \param ev
 */
void XScale::leaveEvent(QEvent *ev)
{
    if(QEvent::Leave == ev->type())
    {
        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::ArrowCursor);         //设置光标形状(箭头)
        setCursor(cursor);                        //使用光标
    }
}

/*!
 * \brief XScale::mousePressEvent
 * \param ev
 */
void XScale::mousePressEvent(QMouseEvent *ev)
{
    if(Qt::LeftButton == ev->button())
    {
        xScaleP->LeftmousePressed = true;
        xScaleP->mousePressPoint = ev->globalPos();

        QCursor cursor;                         //创建光标对象
        cursor.setShape(Qt::ClosedHandCursor);  //设置光标形状(抓)
        setCursor(cursor);                      //使用光标
    }
}

/*!
 * \brief XScale::mouseReleaseEvent
 * \param ev
 */
void XScale::mouseReleaseEvent(QMouseEvent *ev)
{
    if(Qt::LeftButton == ev->button())
    {
        xScaleP->LeftmousePressed = false;

        QCursor cursor;                           //创建光标对象
        cursor.setShape(Qt::PointingHandCursor);  //设置光标形状(指)
        setCursor(cursor);                        //使用光标
    }
}

/*!
 * \brief XScale::mouseMoveEvent
 * \param ev
 */
void XScale::mouseMoveEvent(QMouseEvent *ev)
{
    // 鼠标左键拖动移动
    if(xScaleP->LeftmousePressed)
    {
        double mouseDx = ev->globalPos().x() - xScaleP->mousePressPoint.x();
        double mouseDy = ev->globalPos().y() - xScaleP->mousePressPoint.y();
        xScaleP->mousePressPoint = ev->globalPos();

        double myLabelNewx = this->x() + mouseDx;
        double myLabelNewy = this->y() + mouseDy;

        if(myLabelNewx < 0)
            myLabelNewx = 0;
        if(myLabelNewx + this->width() > QApplication::activeWindow()->width())
            myLabelNewx = QApplication::activeWindow()->width() - this->width();
        if(myLabelNewy < 0)
            myLabelNewy = 0;
        if(myLabelNewy + this->height() > QApplication::activeWindow()->height())
            myLabelNewy = QApplication::activeWindow()->height() - this->height();

        move(myLabelNewx, myLabelNewy);
        update();
    }
}

/*!
 * \brief XScale::getUnitStringParameters
 */
void XScale::getUnitStringParameters(QPainter *painter)
{
    if(xScaleP->unitStringEnable)
    {
        xScaleP->unitStringWidth = painter->fontMetrics().width(xScaleP->unitString);
        xScaleP->unitStringHeight = painter->fontMetrics().height();
    }
    else
    {
        xScaleP->unitStringWidth = 0;
        xScaleP->unitStringHeight = 0;
        return;
    }

    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        xScaleP->unitStringPoint.setX(width() - xScaleP->unitStringWidth - xScaleP->margin);
        xScaleP->unitStringPoint.setY(height() / 2 + xScaleP->unitStringHeight / 2);

        break;
    }
    case Face_Down:
    {
        xScaleP->unitStringPoint.setX(width() - xScaleP->unitStringWidth - xScaleP->margin);
        xScaleP->unitStringPoint.setY(height() / 2 + xScaleP->unitStringHeight / 2);

        break;
    }
    case To_Left:
    {
        xScaleP->unitStringPoint.setX(width() / 2 - xScaleP->unitStringWidth / 2);
        xScaleP->unitStringPoint.setY(height() - xScaleP->margin);

        break;
    }
    case To_Right:
    {
        xScaleP->unitStringPoint.setX(width() / 2 - xScaleP->unitStringWidth / 2);
        xScaleP->unitStringPoint.setY(height() - xScaleP->margin);

        break;
    }
    }
}

/*!
 * \brief XScale::getScaleValueParameters
 * \param painter
 */
void XScale::getScaleValueParameters(QPainter *painter)
{
    QString scaleValue = QString("%1").arg((double)xScaleP->maximumRange, 0, 'f', xScaleP->precision);
    xScaleP->scaleValueWidth = painter->fontMetrics().width(scaleValue);
    xScaleP->scaleValueHeight = painter->fontMetrics().height();
}

/*!
 * \brief XScale::getBaseLinePoint
 */
void XScale::getBaseLineParameters()
{
    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, xScaleP->margin);
        xScaleP->baseLineEndPoint = QPointF(width() - xScaleP->margin - xScaleP->scaleValueWidth / 2 - xScaleP->unitStringWidth, xScaleP->margin);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.x() - xScaleP->baseLineStartPoint.x();

        break;
    }
    case Face_Down:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, height() - xScaleP->margin);
        xScaleP->baseLineEndPoint = QPointF(width() - xScaleP->margin - xScaleP->scaleValueWidth / 2 - xScaleP->unitStringWidth, height() - xScaleP->margin);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.x() - xScaleP->baseLineStartPoint.x();

        break;
    }
    case To_Left:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin, xScaleP->margin + xScaleP->scaleValueHeight / 2);
        xScaleP->baseLineEndPoint = QPointF(xScaleP->margin, height() - xScaleP->margin - xScaleP->scaleValueHeight / 2 - xScaleP->unitStringHeight);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.y() - xScaleP->baseLineStartPoint.y();

        break;
    }
    case To_Right:
    {
        xScaleP->baseLineStartPoint = QPointF(width() - xScaleP->margin, xScaleP->margin + xScaleP->scaleValueHeight / 2);
        xScaleP->baseLineEndPoint = QPointF(width() - xScaleP->margin, height() - xScaleP->margin - xScaleP->scaleValueHeight / 2 - xScaleP->unitStringHeight);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.y() - xScaleP->baseLineStartPoint.y();

        break;
    }
    }
}

/*!
 * \brief XScale::getScaleLineLength
 * \param direction
 * \param margin
 * \param scaleValueW
 * \param scaleValueH
 */
void XScale::getScaleLineLength()
{
    if(Face_UP == xScaleP->scaleDirection || Face_Down == xScaleP->scaleDirection)
    {
        xScaleP->mainScaleLineLength = height() - 2 * xScaleP->margin - xScaleP->scaleValueHeight - 2;
        xScaleP->subScaleLineLength = xScaleP->mainScaleLineLength / 2;
    }
    else
    {
        xScaleP->mainScaleLineLength = width() - 2 * xScaleP->margin - xScaleP->scaleValueWidth - 2;
        xScaleP->subScaleLineLength = xScaleP->mainScaleLineLength / 2;
    }
}

/*!
 * \brief XScale::getScaleLinePoint
 * \param index
 */
void XScale::getScaleLinePoint(QPainter *painter, QPointF &startPoint, QPointF &endPoint, const int index)
{
    //求出刻度线起始点坐标和终止点的坐标
    if(Face_UP == xScaleP->scaleDirection || Face_Down == xScaleP->scaleDirection )
    {
        startPoint.setX(xScaleP->baseLineStartPoint.x() + index * xScaleP->divisionValue);
        startPoint.setY(xScaleP->baseLineStartPoint.y());
        endPoint.setX(startPoint.x());

        if(0 == (index + xScaleP->subScaleNumber + 1) % (xScaleP->subScaleNumber + 1))
        {
            //是主刻度线
            (Face_UP == xScaleP->scaleDirection) ? (endPoint.setY(xScaleP->baseLineStartPoint.y() + xScaleP->mainScaleLineLength))
                                                  : (endPoint.setY(xScaleP->baseLineStartPoint.y() - xScaleP->mainScaleLineLength));

            //设置主刻度画笔颜色
            painter->setPen(xScaleP->mainScaleColor);
        }
        else
        {
            //是副刻度线
            (Face_UP == xScaleP->scaleDirection) ? (endPoint.setY(xScaleP->baseLineStartPoint.y() + xScaleP->subScaleLineLength))
                                                  : (endPoint.setY(xScaleP->baseLineStartPoint.y() - xScaleP->subScaleLineLength));
            //设置基础刻度画笔颜色
            painter->setPen(xScaleP->baseScaleColor);
        }
    }
    else
    {
        startPoint.setX(xScaleP->baseLineStartPoint.x());
        startPoint.setY(xScaleP->baseLineStartPoint.y() + index * xScaleP->divisionValue);
        endPoint.setY(startPoint.y());

        if(0 == (index + xScaleP->subScaleNumber + 1) % (xScaleP->subScaleNumber + 1))
        {
            //是主刻度线
            (To_Left == xScaleP->scaleDirection) ? (endPoint.setX(xScaleP->baseLineStartPoint.x() + xScaleP->mainScaleLineLength))
                                                  : (endPoint.setX(xScaleP->baseLineStartPoint.x() - xScaleP->mainScaleLineLength));

            //设置主刻度画笔颜色
            painter->setPen(xScaleP->mainScaleColor);
        }
        else
        {
            //是副刻度线
            (To_Left == xScaleP->scaleDirection) ? (endPoint.setX(xScaleP->baseLineStartPoint.x() + xScaleP->subScaleLineLength))
                                                   : (endPoint.setX(xScaleP->baseLineStartPoint.x() - xScaleP->subScaleLineLength));
            //设置基础刻度画笔颜色
            painter->setPen(xScaleP->baseScaleColor);
        }
    }
}

/*!
 * \brief XScale::getScaleValueTextPoint
 * \param textPoint
 */
void XScale::getScaleValueTextPoint(QPainter *painter, QString &text, QPointF &textPoint, const QPointF &endPoint, const int index)
{
    //是主刻度时才画刻度值
    if(0 != (index + xScaleP->subScaleNumber + 1) % (xScaleP->subScaleNumber + 1))
        return;

    double currentScaleValue;
    (false == xScaleP->scaleValueReverseOrder) ? (currentScaleValue = xScaleP->minimumRange + index * (xScaleP->maximumRange - xScaleP->minimumRange) / (xScaleP->totalScaleNumber - 1))
                                         : (currentScaleValue = xScaleP->maximumRange - index * (xScaleP->maximumRange - xScaleP->minimumRange) / (xScaleP->totalScaleNumber - 1));
    text = QString("%1").arg(currentScaleValue, 0, 'f', xScaleP->precision);
    double fontWidth = painter->fontMetrics().width(text);
    double fontHeight = painter->fontMetrics().height();

    //分情况设置刻度值坐标
    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        textPoint.setX(endPoint.x() - fontWidth / 2);
        textPoint.setY(endPoint.y() + fontHeight + 2);
        break;
    }
    case Face_Down:
    {
        textPoint.setX(endPoint.x() - fontWidth / 2);
        textPoint.setY(endPoint.y() - 2);
        break;
    }
    case To_Left:
    {
        textPoint.setY(endPoint.y() + fontHeight / 2);
        textPoint.setX(endPoint.x() + 2);
        break;
    }
    case To_Right:
    {
        textPoint.setY(endPoint.y() + fontHeight / 2);
        textPoint.setX(endPoint.x() - fontWidth - 2);
        break;
    }
    }

    //设置刻度值画笔颜色
    painter->setPen(xScaleP->scaleValueColor);
}
